package gomoku;

import java.util.HashMap;
import java.util.Random;
import java.util.Set;

public class AlphaBetaAgent {
	
	public AlphaBetaAgent() {
		
	}
	
	public Move alphaBetaSearch(Board board){//int state[][]){
	
		Move move = new Move(7,7);
		//aB-search
		int cutOff = 3;
		int best = maxValue(cutOff, board, -999999, 999999);
				
		//Find the state identified as best by the aB-search
		//from all the possible successor states created by valid moves.
		HashMap<Board, Move> moves = successorFunction(2,board);
		Set<Board> newStates = moves.keySet();
		for (Board b : newStates){
			if (best == utility(2,b)){
				move = moves.get(b);
				
			}
		}
		
		return move;
	}
	
	public int maxValue(int depth, Board board, int alpha, int beta){
		
		if(depth == 0 || terminalTest(board)) return utility(2, board);
		int value = -999999;
		int localAlpha = alpha;
		
		HashMap<Board, Move> moves = successorFunction(2,board);
		Set<Board> newStates = moves.keySet();		
		for (Board b : newStates){
			value = Math.max(value,(minValue(depth-1, b, localAlpha, beta)));
			if (value >= beta ) return value;
			localAlpha = Math.max(localAlpha, value);			
		}
		
		return value;		
	}

	public int minValue(int depth, Board board, int alpha, int beta){
		
		if(depth == 0 || terminalTest(board)) return utility(1, board);
		int value = 999999;
		int localBeta = beta;
		
		HashMap<Board, Move> moves = successorFunction(1,board);
		Set<Board> newStates = moves.keySet();
		
		for (Board b : newStates){
			value = Math.min(value,(maxValue(depth-1, b, alpha, localBeta)));
			if (value <= alpha ) return value;
			localBeta = Math.min(localBeta, value);			
		}
		
		return value;		
	}
	public HashMap<Board, Move> successorFunction(int player, Board board){
		
		HashMap<Board, Move> tempMap = new HashMap<Board, Move>();
		Board newBoard = new Board(board);
		
		for(int i=0; i<15;i++){
			for(int j=0; j<15;j++){				
				if(newBoard.getPosValue(i, j) == 0){
					newBoard.putStone(i, j, player); //[i][j] = player;
					tempMap.put(newBoard, new Move(i,j));
					newBoard.putStone(i, j, 0);
				}
			}
		}
		
		return tempMap;
	}
	private int utility(int player, Board board){
		
		int totalValue = 0;
		int currentPlayer = 0;
		int oldPlayer = 0;
		int newPlayer = 0;
		int counter = 0;
		
		for(int i=0; i<15;i++){
			for(int j=0; j<15;j++){				
				newPlayer = board.getPosValue(i, j);
				if(newPlayer != currentPlayer){
					totalValue += determinator(oldPlayer, currentPlayer, newPlayer, counter, player);
					oldPlayer = currentPlayer;
					currentPlayer = newPlayer;
					if(newPlayer != 0) counter = 1;
				}
				else{					
					if(newPlayer != 0) counter++;
				}
			}
		}
		return totalValue;
		
	}
	
	private int determinator(int oldplayer, int currentplayer, int newplayer, int counter, int player){
		int score = 0;
		
		if(oldplayer == 0 && newplayer == 0 && currentplayer == player){
			//double/open line, long as counter, playerOwned -> positive
			score = (int) Math.pow(10, counter); 
			
		}
		if(oldplayer == 0 && newplayer == 0 && currentplayer != player){
			//double/open line, long as counter, not playerOwned -> negative
			score = (int) -Math.pow(10, counter);
		}
		if(oldplayer == 0 && newplayer == player){
			//capped line for the other player, negative
			score = (int) -Math.pow(5, counter);
		}
		if(oldplayer == 0 && newplayer != player){
			//capped line for current player, positive
			score = (int) Math.pow(5, counter);
		}
		if(oldplayer == player && newplayer == 0){
			//capped line for the other player, negative
			score = (int) -Math.pow(5, counter);
		}
		if(oldplayer != player && newplayer == 0){
			//capped line for current player, positive
			score = (int) Math.pow(5, counter);
		}
		//other means a line capped at both ends, thus useless
		return score;
	}
	
	private boolean terminalTest(Board board){
		return false;
	}
		
}
